#include "../include/shell.h"
#include "../include/kc.h"
#include "../include/keyboard.h"
#include "../include/string.h"
#include "../include/video.h"
#include "../include/random.h"

#define NUMERO_PRIMO 1001

char *prompt = "Shell $>";
extern int tickpos;
extern void getcpuinfo (void);
extern void getvendorid (void);
extern void getbrand (void);
extern void reset (void);
extern void _kill (int pid);
extern void _renice (int prioridad, int pid);
extern void _top (void);

comando lista[] = {
    {"clear", "Limpia la pantalla.", limpiaPantalla},
    {"cpuinfo", "Imprime informacion sobre el procesador", cpuinfo},
    {"fortune", "Imprime una frase aleatoria.", fortune},
    {"help", "Muestra los comandos disponibles.", imprimeAyuda},
    {"top", "Muestra el porcentaje de consumo de cada proceso.", top},
    {"renice", "Cambiar la prioridad de un proceso.", renice},
    {"mallocInfinito", "Verificar que malloc no explota :)", mallocInf},
    {"kill", "Mata a un proceso.", kill},
    {"colgame", "Sirve para verificar kill y renice ;-)", colgado},
    {"explota", "Proceso malo que genera un Page Fault.", test},
    {"shmemread", "lee de la zona de memoria con key 2", shmemRead},
    {"shmemwrite", "escribe en la zona de memoria con key 2", shmemWrite},
    {"dividecero", "divide por cero :D", divideByZero}

};

int
shell (int a, char **aux) {
    char bufferShell[MAXLONGITUD];
    char argumentos[MAX_ARGC][MAX_ARG];
    char usuario[MAXLONGITUD - 2];
    int background, cmdLen, c, i, offset, comienzo, posActual, argc;

    comienzo = posActual = argc = background = 0;

    imprimePrompt ();
    while (1) {
        
        bufferShell[0] = 0;
        cmdLen = 0;


        while ((c = getChar ()) != '\n') {

            if (c != '\b') {
                /* la linea que tipeo cambio, quiero que aparezca como
                 * ultima opcion */
                bufferShell[posActual] = c;
                bufferShell[posActual + 1] = 0;
                posActual++;
                putchar (c);
            }
            else if (posActual != 0) {
                posActual--;
                bufferShell[posActual] = 0;
                putchar (c);
            }
        }
        offset = 0;

        for (i = 0; i < posActual; i++) {
            if (cmdLen == 0 && bufferShell[i] == ' ') {
                offset++;
                continue;
            }

            if (bufferShell[i] == '\t')
                break;

            /*Parseo de argumentos para kill y renice */
            if (bufferShell[i] == ' ') {
                int len, len2;
                len = strlen ("renice");
                len2 = strlen ("kill");
                if (strncmp (bufferShell + offset, "renice", len) == 0
                    || strncmp (bufferShell + offset, "kill", len2) == 0) {
                    i++;
                    int k = 0;
                    while (bufferShell[i] == ' ') {
                        i++;
                    }
                    while (bufferShell[i] != ' ' && bufferShell[i] != '\n'
                           && i < posActual) {
                        if (bufferShell[i] == '\t') {
                            i--;
                            break;
                        }
                        if (argc < MAX_ARGC) {
                            if (k < MAX_ARG) {
                                argumentos[argc][k] = bufferShell[i];
                            }
                        }
                        i++;
                        k++;
                    }
                    if (bufferShell[i + 1] == '\t') {
                        break;
                    }
                    argumentos[argc][k] = '\n';
                    argc++;

                    if (bufferShell[i] == ' ')
                        i--;
                }
                else
                    break;
            }

               /*-----------------------------------------------*/
            cmdLen++;
        }

        /* chequear si esta en background, TODO: no cablearlo */
        if (bufferShell[posActual - 1] == '&') {
            background = 1;
            bufferShell[posActual - 1] = 0;
        }
        else {
            background = 0;
        }

        /* finalizo la cadena tipeada e imprimo el enter */
        bufferShell[posActual] = 0;
        putchar ('\n');

        /* si posActual != 0 es porque hubo algun comando tipeado */
        if (posActual != 0) {
            ejecutaComando (bufferShell + offset, argc, argumentos,
                            background);
        }

        posActual = 0;
        argc = 0;

        /* be nice to mommy and wait :D */
        asm volatile ("hlt");
        asm volatile ("hlt");
        asm volatile ("hlt");
        imprimePrompt ();
    }
}

void
limpiaLinea (void) {
    int i;
    int fila;
    int len = 2;

    fila = tickpos / (COLS * 2);
    tickpos = fila * COLS * 2 + len * 2;

    for (i = len + 1; i < COLS; i++)
        putchar (' ');

    tickpos = fila * COLS * 2 + len * 2;
    update_cursor (tickpos / 160, (tickpos % 160) / 2);
}


void
ejecutaComando (char *cmd, int argc, char argumentos[MAX_ARGC][MAX_ARG],
                int background) {
    char msg[] = "Escriba help para una lista de comandos.\n";
    int cantidad;
    int encontrado;
    int len;
    int i;

    encontrado = 0;
    cantidad = sizeof (lista) / sizeof (lista[0]);
    len = strlen ("renice");
    /*Si es un renice */
    if (strncmp (cmd, "renice", len) == 0
        && (cmd[len] == 0 || cmd[len] == ' ')) {
        renice (argc, (char **) argumentos);
        return;
    }
    len = strlen ("kill");
    /*Si es un kill */
    if (strncmp (cmd, "kill", len) == 0 && (cmd[len] == 0 
                || cmd[len] == ' ')) {
        kill (argc, (char **) argumentos);
        return;
    }

    len = strlen ("dividecero");
    if (strncmp (cmd, "dividecero", len) == 0 && (cmd[len] == 0
                || cmd[len] == ' ')) {
        ejecutar (lista[12].nombre, lista[12].funcion, 1);
        return;
    }

    len = strlen("explota");
    if (strncmp (cmd, "explota", len) == 0 && (cmd[len] == 0 || cmd[len] == ' ')) {
        ejecutar (lista[9].nombre, lista[9].funcion, 1);
        return;
    }

    for (i = 0; !encontrado && i < cantidad; i++) {
        len = strlen (lista[i].nombre);
        if (strncmp (cmd, lista[i].nombre, len) == 0 && cmd[len] == 0) {
            encontrado = 1;
            ejecutar (lista[i].nombre, lista[i].funcion, background);
        }
    }

    if (!encontrado)
        printf (msg, strlen (msg));
}

int
divideByZero(int argc, char **argv) {
    int i;

    i = 2 / 0;
    return 0;
}

int
cpuinfo (int argc, char **argv) {
    char vid[] = "Vendor ID:";
    char ff[] = "Features:";
    char marca[] = "Brand:";

    printf (vid, 10);
    putchar ('\n');

    getvendorid ();
    putchar ('\n');

    printf (ff, 9);
    putchar ('\n');

    getcpuinfo ();
    putchar ('\n');

    printf (marca, 6);
    putchar ('\n');

    getbrand ();
    putchar ('\n');
}

int fortuneviejo = 0;

int
shmemRead (int argc, char **argv) {
    int key, id;
    int i;
    int len;
    char *data;

    // pido un bloque de 512 bytes compartido
    key = 2;
    id = shmGet(key, 512);
    data = (char *) shmAt(id);

    while (1) {
        if (shmLock(id) != -1) {
            len = strlen(data);

            for (i = 0; i < len; i++)
                putchar(data[i]);
            putchar ('\n');

            shmUnlock(id);
            printf ("Lector: lei\n", 12);
        }
        else {
            printf ("Lector: Lockeado - Esperando\n", 29);
        }
        //sleep (1);
    }
    return 0;
}

int
shmemWrite (int argc, char **argv) {
    int key, id;
    int i, j;
    char *data;
    char *strings[] = {"hola", "chau", "eaea"};

    key = 2;
    id = shmGet(key, 512);
    data = (char *) shmAt(id);

    j = 0;
    while (1) {
        if (shmLock(id) != -1) {
            for (i = 0; i < 512; i++)
                data[i] = 0;

            for (i = 0; i < strlen(strings[j]); i++)
                data[i] = strings[j][i];

            j = (j + 1) % 3;
            printf("Escritor: escribi\n", 18);
            shmUnlock(id);
        }
        else
            printf("Escritor: Lockeado\n", 19);

        sleep (1);
    }
    return 0;
}

int
fortune (int argc, char **argv) {
    int rand;
    int cant;

    static char frases[][MAXLONGITUD] = {
        "El arte de ser sabio es el arte de saber que es lo que debemos "
            "ignorar.\n- William James",
        "La inspiracion existe, pero tiene que encontrarte trabajando."
            "\n- Pablo Picasso",
        "La arquitectura es el arte de desperdiciar espacio.\n"
            "- Phillip Johnson",
        "La ciencia es la progresiva aproximacion del hombre al mundo real. "
            "\n- Max Planck",
        "Se dice que si conoces a los demas y te conoces a ti mismo, ni en "
            "cien batallas correras peligro.\n- Sun Tzu",
        "Si no puedes convencerlos, confundelos.\n- Harry Truman",
        "No se como sera la tercera guerra mundial, solo se que la cuarta "
            "sera con piedras y lanzas.\n- Albert Einstein",
        "No hay camino para la paz, la paz es el camino.\n- Gandhi",
        "La revolucion se lleva en el corazon, no en la boca para vivir de "
            "ella.\n- Ernesto Guevara",
        "Una derrota peleada vale mas que una victoria causal.\n- San Martin"
 
    };

    cant = sizeof (frases) / sizeof (frases[0]);
    rand = random (cant, &fortuneviejo);

    printf (frases[rand], strlen (frases[rand]));
    putchar ('\n');
}



int
mallocInf (int argc, char **argv)
{
    char *tmp;

    tmp = (char *) malloc(512);
    while (tmp != 0x0) {
        printf("malloc me dio: 512 bytes\n", 25);
        tmp = (char *) malloc(512);
    }
    printf("No tengo mas heap :(\n", 21);
}

int
kill (int argc, char **argv) {
    char *argvaux = (char *) argv;
    int numero;
    if (argc == 1 && (numero = atoi (argvaux)) != -1) {

        _kill (numero);

    }
    else
        printf ("Mal ingreso de parametros.\n", 27);

}
int
colgado(int argc, char **argv){
	int i;
	char s[5];
    while(1){
	sleep(1);
	itoa(i,s);
	printf(s,1);
	
	}
   /*asm volatile("hlt");*/
/*    }*/
}
int
renice (int argc, char **argv) {
    int n1, n2;
    char *argvaux = (char *) argv;
    if (argc == 2 && (n1 = atoi (argvaux)) != -1 &&
        (n2 = atoi (argvaux + 1 * MAX_ARG)) != -1) {

        _renice (n1, n2);
    }
    else
        printf ("Mal ingreso de parametros.\n", 27);

}



int
imprimeAyuda (int argc, char **argv) {
    int i;
    int cantidad;

    cantidad = sizeof (lista) / sizeof (lista[0]);

    for (i = 0; i < cantidad; i++) {
        printf (lista[i].nombre, strlen (lista[i].nombre));
        putchar ('\t');
        putchar ('\t');
        printf (lista[i].descripcion, strlen (lista[i].descripcion));
        putchar ('\n');
    }
}

void
imprimePrompt (void) {
    printf (prompt, 8);
}

int
limpiaPantalla (int argc, char **argv) {
    int i;

    /* empezar desde la primera posicion */
    tickpos = 0;
    for (i = 0; i < FILAS * COLS * 2; i += 2)
        putchar (' ');

    /* el prompt se debe imprimir en la primera linea */
    tickpos = 0;
    update_cursor (0, 0);
}
